<?php

namespace app\index\controller;

use app\index\common\Common;
use app\index\model\News;
use app\index\model\Order;
use app\index\model\OrderHistory;
use app\index\model\OrderPayment;;
use app\index\model\Product;
use think\Controller;
use think\Exception;
use think\Request;

class IPN extends Controller
{

    public function __construct(Request $request = null)
    {
        parent::__construct($request);
    }

    public function getIPNResponse()
    {
        $callBack=input('post.');
        $OrderPaymentClass=new OrderPayment();
        $OrderClass=new Order();
//        $News=new News();

        $OrderClass->startTrans();
        try {
            if(empty($callBack)){
                throw new Exception('callBack is empty');
            }
            if($callBack['payment_status']==='Reversed' || $callBack['payment_status']==='Canceled_Reversal'){
                trace('Paypal Callback Error. payment_status error
                '.json_encode($callBack),'error');
                return json(['success'],200);
            }
            $orderData=[];
            $order_payment = [];
            if(isset($callBack['invoice']) && !empty($callBack['invoice'])){
                $order = [];
                $orderData = $OrderClass
                    ->where('receipt_number', $callBack['invoice'])
                    ->where('del_flag',0)
                    ->field('id,create_user,total_price,amount_discount,create_group')
                    ->find();
                if(empty($orderData)){
                    trace('orderData is empty'.json_encode($callBack),'error');
                    return json([],200);
                }
                $orderData = $orderData->toArray();
            }
            if(!isset($callBack['mc_gross'])){
                if($callBack['txn_type']==='new_case') {
                    /*$news_data = [
                        'order_id' => $orderData['id'],
                        'type' => 1,
                        'group' => $orderData['create_group'],
                    ];
                    if(isset($callBack['case_type'])){
                        $news_data['content']='new case '.$callBack['case_type'];
                    }
                    $News->insert($news_data);*/
                    return json(['success'], 200);
                }
                throw new Exception('txn_type error');
            }
            if(!empty($orderData)){
                if($callBack['mc_gross'] > 0){
                    $order['id'] = $orderData['id'];
                    $order['payment_time'] = date('Y-m-d H:i:s',strtotime($callBack['payment_date']));
                    $OrderClass->data($order);
                    $result = $OrderClass->isUpdate(true)->save();
                    if ($result === false) {
                        throw new Exception('save Order error');
                    }
                    $order_payment['payment_type'] = 1;
                    $order_payment['amount'] = $callBack['mc_gross'];
                    $order_payment['mc_fee'] = $callBack['mc_fee'];
                }else{
                    $order['id'] = $orderData['id'];
                    $order_payment['payment_type'] = 2;
                    $order_payment['amount'] = abs($callBack['mc_gross']);
                    $order_payment['mc_fee'] = abs($callBack['mc_fee']);
                }
            }

            $order_payment['payment_date'] =  date('Y-m-d H:i:s',strtotime($callBack['payment_date']));
            $order_payment['order_id'] = $order['id'] ?? null;
            $order_payment['payer_email'] = $callBack['payer_email'];
            $order_payment['receiver_email'] = $callBack['receiver_email'];
            $order_payment['create_user'] = 0;

            if(!empty($callBack['txn_id'])){
                $order_payment['invoice_payment_id'] = $callBack['txn_id'];
                $obj = $OrderPaymentClass->field('id')->where('invoice_payment_id',$callBack['txn_id'])->find();
                if(empty($obj)){
                    $OrderPaymentClass->data($order_payment);
                    $result = $OrderPaymentClass->save();
                }else{
                    $order_payment['id'] = $obj->id;
                    $result = $OrderPaymentClass->isUpdate(true)->save($order_payment);
                }
                if ($result === false) {
                    throw new Exception('save Order Payment error');
                }
            }else{
                throw new Exception('tnx_id is empty');
            }

            $OrderClass->commit();
            return json(['success'],200);
        }catch (Exception $e){
            $OrderClass->rollback();
            trace('Paypal Callback Error.
            '.$e->getMessage().'
            '.json_encode($callBack),'error');
            return json([],500);
        }
    }

    public function getWebhookResponse(){
        $json_data=input('put.');
        try {
            $OrderClass=new Order();
            $OrderHistoryClass=new OrderHistory();
            $OrderPaymentClass=new OrderPayment();

            $invoice = $json_data['resource']['invoice'];
            $event_type=$json_data['event_type'];
            $pay_status=$invoice['status'];
            switch ($pay_status){
                case 'DRAFT': $pay_status=1;
                    break;
                case 'SENT': $pay_status=2;
                    break;
                case 'PARTIALLY_PAID': $pay_status=3;
                    break;
                case 'MARKED_AS_PAID':
                case 'PAID': $pay_status=4;
                    break;
                case 'CANCELLED':$pay_status=5;
                    break;
                case 'REFUNDED': $pay_status=7;
                    break;
                case 'PARTIALLY_REFUNDED': $pay_status=6;
                    break;
                default:
                    throw new Exception('Paypal Webhook Error.
                    Unknown paypal pay_type.'.$invoice['status']);
            }
            if($event_type==='INVOICING.INVOICE.UPDATED' || $event_type==='INVOICING.INVOICE.CREATED'){
                if($pay_status===1 || $pay_status===2) {
                    return json([], 200);
                }
            }
            if(isset($invoice['gratuity'])) {
                $tip = $invoice['gratuity']['value'];
            }else{
                $tip=0;
            }

            $receipt_number=$invoice['id'];
            $order_id=$invoice['detail']['invoice_number'];

            $old_order=Order::alias('o')->join('__CUSTOMER__ c','o.customer_id=c.id','left')->where('o.order_id',$order_id)->where('o.receipt_number',$receipt_number)->where('o.del_flag',0)->field('o.id,o.email,o.pay_type,o.create_user,o.create_group,o.total_price,c.nick_name,o.customer_id')->find();
            if(empty($old_order)){
                trace('Paypal Webhook Error.
                Cant find order.'.$receipt_number,'error');
                return json([],200);
            }
            $id=$old_order['id'];
            if(!isset($invoice['payments']) && $pay_status!==5){
                return json(['已取消'],200);
            }
            if($old_order['pay_type']===4 && $pay_status===4){
                return json(['已修改状态'],200);
            }

            $insert_list=[];
            //判断付款和退款，处理要添加的数据
            if($pay_status===6 || $pay_status===7 || $event_type==='INVOICING.INVOICE.REFUNDED'){
                $refund_amount=$invoice['refunds']['refund_amount']['value'];
                $refunds_transactions=end($invoice['refunds']['transactions']);
                $refunds_transaction_list=$invoice['refunds']['transactions'];

                foreach ($refunds_transaction_list as $key=>$value) {
                    $arr=$OrderPaymentClass->where('invoice_payment_id',$value['recipient_transaction_id'])->where('del_flag',0)->where('order_id',$id)->find();
                    if(empty($arr)){
                        $insert_list[]=['order_id' => $id,'payment_type'=>2, 'type' => $value['type'] === 'PAYPAL' ? 0 : 1, 'invoice_payment_id' => $value['recipient_transaction_id'], 'method' => 'PAYPAL', 'payment_date' => $value['refund_date'], 'amount' => $value['amount']['value'],'create_user'=>0];
                    }
                }
                $order=['amount_refund'=>$refund_amount,'pay_type'=>$pay_status];
                $order_history=['order_id'=>$id,'operator'=>0,'operational'=> '退款给'.$old_order['email'].'.'.$refunds_transactions['amount']['value'].$refunds_transactions['amount']['currency_code']];
            }else if ($pay_status===5  || $event_type==='INVOICING.INVOICE.CANCELLED'){
                if($old_order['pay_type']===5){
                    return json(['code'=>1,'msg'=>[]],200);
                }
                $order=['pay_type'=>$pay_status,'order_status'=>2];
                $order_history=['order_id'=>$id,'operator'=>0,'operational'=> '客户取消订单'];
            }elseif($pay_status===3 || $pay_status===4 || $event_type==='INVOICING.INVOICE.PAID'){
                $paid_amount=$invoice['payments']['paid_amount']['value'];
                $transactions=end($invoice['payments']['transactions']);
                $transaction_list=$invoice['payments']['transactions'];

                foreach ($transaction_list as $key=>$value) {
                    $arr=$OrderPaymentClass->where(function ($query)use($value){
                        $query->where('invoice_payment_id',$value['payment_id'])->whereOr('payment_id',$value['payment_id']);
                    })->where('del_flag',0)->where('order_id',$id)->find();
                    if(empty($arr)){
                        $insert=[
                            'order_id' => $id,
                            'payment_type'=>1,
                            'type' => $value['type'] === 'PAYPAL' ? 0 : 1,
                            'invoice_payment_id' => null,
                            'payment_id'=>null,
                            'method' => $value['method'],
                            'payment_date' => $value['payment_date'],
                            'amount' => $value['amount']['value'],
                            'create_user'=>0
                        ];
                        if($insert['type']===1){
                            $insert['payment_id']=$value['payment_id'];
                        }else{
                            $insert['invoice_payment_id']=$value['payment_id'];
                        }
                        $insert_list[]=$insert;
                    }
                }
                $order=['amount_paid'=>$paid_amount,'tip_paid'=>$tip,'pay_type'=>$pay_status];
                $order_history=['order_id'=>$id,'operator'=>0,'operational'=>'用户 '.$old_order['nick_name'].' 付款. '.$transactions['amount']['value'].$transactions['amount']['currency_code']];

                try {
                    Common::paymentNotice($old_order['create_user'], $old_order['create_group'], [
                        'type' => 'push',
                        'key' => 'home_payment_list',
                        'msg' => $old_order['nick_name'] . '付款 ' . $transactions['amount']['value'] . $transactions['amount']['currency_code'],
                        'data' => [
                            'amount' => $transactions['amount']['value'],
                            'amount_paid' => $paid_amount,
                            'is_new' => true,
                            'nick_name' => $old_order['nick_name'],
                            'customer_id' => $old_order['customer_id'],
                            'order_id' => $order_id,
                            'ship_status' => $paid_amount >= 500,
                            'total_price' => $old_order['total_price'],
                            'payment_date' => $transactions['payment_date'],
                        ]],'order');
                }catch (Exception $e){
                    trace('ipn payment notice error'.$e->getMessage(),'error');
                }

            }

            $OrderClass->startTrans();
            try{
                $result=$OrderClass->isUpdate()->save($order,['id'=>$id]);
                if($result===false){
                    throw new Exception('Update Order error');
                }
                $result=$OrderHistoryClass->insert($order_history);
                if($result===false){
                    throw new Exception('insert Order History error');
                }

                if(!empty($insert_list)) {
                    $result = $OrderPaymentClass->isUpdate(false)->saveAll($insert_list);
                    if ($result === false) {
                        throw new Exception('insert Order Payment error');
                    }
                }

                $OrderClass->commit();
            }catch (Exception $e){
                $OrderClass->rollback();
                throw new Exception('Paypal Webhook Error.
                    Update Error'.$e);
            }
            if($pay_status===4) {
                ['status' => $status, 'result' => $result] = Product::lockStockByOrder($id);
                if ($status === false) {
                    trace('paypal lock stock error' . json_encode($result), 'error');
                }
            }elseif($pay_status===5){
                ['status'=>$status,'result'=>$result]=Product::cancelOrderDemandStock($id);
                if ($status === false) {
                    trace('paypal cancel stock error' . json_encode($result), 'error');
                }
            }
            return json(['success'],200);
        }catch (Exception $e){
            trace('Paypal Webhook Error.
            '.$e->getMessage(),'error');
            return json([],500);
        }
    }

}